package sketch.util;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.LinkedList;
import java.util.List;

import randoop.util.Files;

import junit.framework.TestCase;

public class Counter extends TestCase {

	//count the number of unit tests
	
	public static List<Method> getJUnitMethods(Class<?> clazz, boolean countTest) {
		List<Method> list = new LinkedList<Method>();
		if(!junit.framework.TestCase.class.isAssignableFrom(clazz)) {
			return list;
		}
		
		for(Method m: clazz.getDeclaredMethods()) {
			String methodName = m.getName();
			boolean isTest = methodName.startsWith("test") && Modifier.isPublic(m.getModifiers())
			    && m.getReturnType().equals(void.class);
			if(countTest && isTest) {
				list.add(m);
			} else if(!countTest && !isTest) {
				list.add(m);
			}
		}
		
		return list;
	}
	
	public static List<Class<?>> getClasses(String dir, String packagePrefix) {
		File topDir = new File(dir);
		Checker.checkTrue(topDir.isDirectory(), "The dir is not a dir: " + dir);
		
		List<File> fileList = new LinkedList<File>();
		
		//the file
		List<File> list = new LinkedList<File>();
		for(File f : topDir.listFiles()) {
			list.add(f);
		}
		while(!list.isEmpty()) {
			File f = list.remove(0);
			if(f.isFile()) {
				fileList.add(f);
			} else {
				File[] subFiles = f.listFiles();
				for(File subFile : subFiles) {
					list.add(subFile);
				}
			}
		}
		
		List<Class<?>> clazzList = new LinkedList<Class<?>>();
		for(File f : fileList) {
			if(!f.getName().endsWith(".class")) {
				continue;
			} else {
				String absolutePath = f.getAbsolutePath();
				String className = SketchUtil.transClassNameSlashToDot(
						absolutePath.substring(dir.length() + 1, absolutePath.length() - ".class".length())
						);
				Class<?> clz = null;
				try {
					clz = Class.forName(className);
					if(packagePrefix == null) {
						clazzList.add(clz);
					} else if (clz.getPackage().getName().startsWith(packagePrefix)) {
					    clazzList.add(clz);
					}
				} catch (Exception e) {
					System.err.println("error: " + className);
				}
			}
		}
		
		return clazzList;
	}
	
	public static List<Method> countTestMethod(String dir, String packagePrefix) {
		List<Class<?>> allClasses = getClasses(dir, packagePrefix);
		List<Method> retClasses = new LinkedList<Method>();
		
		for(Class<?> clz : allClasses) {
			retClasses.addAll(getJUnitMethods(clz, true));
		}
		
		return retClasses;
	}
	
	public static List<Method> countAuxiliaryMethod(String dir, String packagePrefix) {
		List<Class<?>> allClasses = getClasses(dir, packagePrefix);
		List<Method> retClasses = new LinkedList<Method>();
		
		for(Class<?> clz : allClasses) {
			retClasses.addAll(getJUnitMethods(clz, false));
		}
		
		return retClasses;
	}
	
	public void testDumpAllAuxiliaryMethods() throws IOException {
		System.out.println("Dumping all apache non-testing methods: ");
		String dir = "/scratch/eclipseworkspace/apache-common-collection-3.2.1/bin";
		String packagePrefix = "org.apache.commons.collections";
		List<Method> methods = countAuxiliaryMethod(dir, packagePrefix);
		StringBuilder sb = new StringBuilder();
		for(Method m : methods) {
			sb.append(m.toString());
			sb.append(Globals.lineSep);
		}
		sb.append("Total method num: " + methods.size());
		randoop.util.Files.writeToFile(sb.toString(), "./apache-all-auxiliary-methods.txt");
		System.out.println("Dumping finishes: " + "./apache-all-auxiliary-methods.txt");
	}
	
	public void testSummarizingNums() throws IOException {
		String filePath = "./org.apache.commons.collections.txt";
		List<String> lines = Files.readWhole(new File(filePath));
		int before = 0;
		int after = 0;
		for(String line : lines) {
			if(line.trim().isEmpty()) {
				continue;
			}
			line = line.trim();
			String beforeStr = line.substring(0, 1);
			String afterStr = line.substring(line.length() - 1);
			try {
			  before = before + Integer.valueOf(beforeStr);
			  after = after + Integer.valueOf(afterStr);
			} catch (NumberFormatException e) {
				continue;
			}
		}
		System.out.println("Before: " + before + ",  after: " + after);
	}
	
	public void testDumpAllTestMethodInApache() throws IOException {
		System.out.println("Dumping all apache testing methods: ");
		String dir = "/scratch/eclipseworkspace/apache-common-collection-3.2.1/bin";
		String packagePrefix = "org.apache.commons.collections";
		List<Method> methods = countTestMethod(dir, packagePrefix);
		StringBuilder sb = new StringBuilder();
		for(Method m : methods) {
			sb.append(m.toString());
			sb.append(Globals.lineSep);
		}
		sb.append("Total method num: " + methods.size());
		randoop.util.Files.writeToFile(sb.toString(), "./apache-all-methods.txt");
		System.out.println("Dumping finishes: " + "./apache-all-methods.txt");
	}
	
	
}